package cn.lucky.core;

import cn.lucky.annotation.Lazy;
import cn.lucky.annotation.MyComponent;
import cn.lucky.annotation.Scope;
import cn.lucky.constant.ScopeType;
import cn.lucky.ex.NoSuchBeanDefinitionException;
import cn.lucky.test.controller.HelloController;
import cn.lucky.vo.SimpleBeanDefinition;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class SimpleIOCDemo {

    //保存bean定义的map ，只要添加了注解的类，都会保存到这个map中
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    // 保存bean实例map
    private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();

    public SimpleIOCDemo(){

    }
    public SimpleIOCDemo(String basePackage) throws Exception{
        ClassScanner scanner = new ClassScanner();
        // 获得根包下面的所有类对象
        List<Class<?>> classes = scanner.findClasses(basePackage);
        // 处理类对象是否可以添加到这两个map中去
        for (Class<?> aClass : classes) {
            MyComponent annotation = aClass.getAnnotation(MyComponent.class);
            Scope annotation1 = aClass.getAnnotation(Scope.class);
            Lazy lazy = aClass.getAnnotation(Lazy.class);
            ScopeType scope = annotation1 == null? ScopeType.SINGLETON:annotation1.value();

            if(annotation!=null){
                // 第一我们需要把描述这个类的信息，封装到BeanDefinition对象中，并且添加到map
                SimpleBeanDefinition beanDefinition = new SimpleBeanDefinition();
                beanDefinition.setBeanClass(aClass);
                beanDefinition.setScope(scope);
                //如果是懒加载，那么就设置懒加载
                if(lazy!=null){
                    beanDefinition.setLazy(true);
                }

                String beanName=aClass.getName().substring(aClass.getName().lastIndexOf(".")+1).toLowerCase();
                beanDefinitionMap.put(beanName,beanDefinition);
                // 魔法值 "singleton"

                if( ScopeType.SINGLETON.equals(scope) && !beanDefinition.isLazy()){
                    singletonObjects.put(beanName,aClass.newInstance());
                }

            }
        }
        System.out.println("beanDefintionMap:"+beanDefinitionMap);
        System.out.println("singletonObjects:"+singletonObjects);


    }

    // 提供对外的get方法
    public Object getBean(String beanName){
        // 处理单例和多例
        beanName = beanName.toLowerCase();
        Object o = singletonObjects.get(beanName);
        if(o==null){
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if(beanDefinition==null){
                throw new NoSuchBeanDefinitionException("noSuchBeanDefinition:"+beanName);
            }
            // 如果是多例 直接new return ，不用放singletonMap
            ScopeType scope = beanDefinition.getScope();
            if(ScopeType.PROTOTYPE.equals(scope)){
                Class<?> beanClass = beanDefinition.getBeanClass();
                try {
                    o=beanClass.newInstance();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
            // 如果是懒加载，就先new  put到单例map中
            if(beanDefinition.isLazy()){
                Class<?> beanClass = beanDefinition.getBeanClass();
                try {
                    o=beanClass.newInstance();
                    singletonObjects.put(beanName,o);
                    System.out.println("singletonObjects:"+singletonObjects);
                }catch (Exception e){
                    throw new RuntimeException(e);
                }
            }
        }
        return o;
    }

    // 泛型方法优化getBean
    public <T>T getBean(String beanName,Class<T> cls){
        return (T)getBean(beanName);
    }


    public static void main(String[] args) throws Exception {
        SimpleIOCDemo simpleIoC = new SimpleIOCDemo("cn.lucky");
        HelloController helloController = simpleIoC.getBean("helloController", HelloController.class);
        helloController.sayHello();
    }
}
